﻿using System;
using System.IO.Ports;
using System.Threading;

namespace sinetd.Protocols.Serial
{
    public class Protocol : BaseProtocol, IProtocol
    {
        private SerialPort serialPort;

        public override void ConfigDefault()
        {
            cfg.SetDefault("TextMode", "true");

            cfg.SetDefault("port", "COM1");
            cfg.SetDefault("BaudRate", "115200");
            cfg.SetDefault("Parity", "0");
            cfg.SetDefault("DataBits", "8");
            cfg.SetDefault("StopBits", "1");
            cfg.SetDefault("RtsEnable", "true");
        }

        public override void ConfigChanged()
        {
            serialPort.Encoding = System.Text.Encoding.GetEncoding(1252);

            serialPort.PortName = cfg.GetString("port");
            serialPort.BaudRate = cfg.GetInt32("BaudRate");
            serialPort.Parity = (Parity)cfg.GetInt32("Parity");
            serialPort.DataBits = cfg.GetInt32("DataBits");
            serialPort.StopBits = (StopBits)cfg.GetInt32("StopBits");
            serialPort.RtsEnable = cfg.GetBoolean("RtsEnable");
        }

        public Protocol() : base("Serial")
        {
            serialPort = new SerialPort();
        }

        #region IProtocol Members

        private bool inUse = false;

        public void Bind(AcceptClientHandler AcceptClient)
        {
            StartThread(() =>
            {
                try
                {
                    serialPort.Open();
                }
                catch { TerminatePending = true; }

                serialPort.DataReceived += new SerialDataReceivedEventHandler((object sender, SerialDataReceivedEventArgs e) =>
                {
                    if (!inUse)
                    {
                        inUse = true;
                        AcceptClient(this);
                        inUse = false;
                    }
                });
                while (!TerminatePending) Thread.Sleep(100);
            });
        }

        public bool Connect()
        {
            serialPort.Open();
            serialPort.WriteTimeout = 5000;
            serialPort.ReadTimeout = 5000;
            return true;
        }

        public void Send(string msg)
        {
            try
            {
                inUse = true;
                if (cfg.GetBoolean("TextMode"))
                    serialPort.WriteLine(msg);
                else
                    serialPort.Write(msg);
                inUse = false;
            }
            catch (TimeoutException)
            {
            }
        }

        public string Recv()
        {
            string ret = "";
            //try
            //{
            inUse = true;
            if (cfg.GetBoolean("TextMode"))
                ret = serialPort.ReadLine();
            else
                ret = serialPort.ReadExisting();
            inUse = false;
            //}
            //catch (TimeoutException)
            //{
            //}
            return ret;
        }

        public void Close()
        {
            StopThread();
            serialPort.Close();
        }

        #endregion
    }
}
